import _ from 'lodash'
import React, {ReactElement} from 'react'
import {ComplexPropertyValue, PromiseMabe, YvanEvent} from "../types";
import {VJsonComponentBase} from "../factory";
import * as mobx from 'mobx'

/**
 * 将 hash 描述转换为 planObject 对象
 */
export function unparam(query: string): any {
    const queryString: any = {};
    if (query.slice(0, 1) === "#") {
        query = query.slice(1);
    }
    const vars = query.split("&");
    for (let i = 0; i < vars.length; i++) {
        const pair = vars[i].split("=");
        pair[0] = decodeURIComponent(pair[0]);
        pair[1] = decodeURIComponent(pair[1]);
        // If first entry with this name
        if (typeof queryString[pair[0]] === "undefined") {
            queryString[pair[0]] = pair[1];
        } else if (typeof queryString[pair[0]] === "string") {
            const arr = [queryString[pair[0]], pair[1]];
            queryString[pair[0]] = arr;
        } else {
            queryString[pair[0]].push(pair[1]);
        }
    }
    return queryString;
}

/**
 * 为某个事件绑定一个代理方法, 使其按照 YvanEvent 的方式调用事件
 */
export function YvanEventBind<T extends VJsonComponentBase<any, any>>(event: YvanEvent<T> | undefined, sender: T) {
    if (!event) {
        // 没有绑定事件
        return undefined;
    }
    return function () {
        YvanEventDispatch(event, sender, arguments)
    }
}

/**
 * 将获取值的方法，或值本身，变换为值
 */
export function apply<T>(sender: any, t: T | (() => T)): T {
    if (typeof t === "function") {
        // @ts-ignore
        return t(sender)
    }
    return t
}

export function convertCH(str: string) {
    // let result = "";
    // for (let i = 0; i < str.length; i) {
    //     if (str.charCodeAt(i) == 12288) {
    //         result = String.fromCharCode(str.charCodeAt(i) - 12256);
    //         continue;
    //     }
    //     if (str.charCodeAt(i) > 65280 && str.charCodeAt(i) < 65375)
    //         result = String.fromCharCode(str.charCodeAt(i) - 65248);
    //     else
    //         result = String.fromCharCode(str.charCodeAt(i));
    // }
    // return result;

    let tmp = "";
    for (let i = 0; i < str.length; i++) {
        if (str.charCodeAt(i) > 65248 && str.charCodeAt(i) < 65375) {
            tmp += String.fromCharCode(str.charCodeAt(i) - 65248);
        } else {
            tmp += String.fromCharCode(str.charCodeAt(i));
        }
    }
    tmp = tmp.replace(/。/g, ".")
    tmp = tmp.replace(/，/g, ",")
    tmp = tmp.replace(/？/g, "?")
    // tmp = tmp.replace(/《/g, "<")
    // tmp = tmp.replace(/》/g, ">")
    tmp = tmp.replace(/！/g, "!")
    tmp = tmp.replace(/（/g, "(")
    tmp = tmp.replace(/）/g, ")")
    tmp = tmp.replace(/：/g, ":")
    tmp = tmp.replace(/“/g, '\\"')
    tmp = tmp.replace(/”/g, '\\"')
    tmp = tmp.replace(/‘/g, "'")
    tmp = tmp.replace(/’/g, "'")
    tmp = tmp.replace(/【/g, "[")
    tmp = tmp.replace(/】/g, "]")
    return tmp

    // str = str.replace(/，/g, ",")
    // str = str.replace(/。/g, ".")
    // str = str.replace(/【/g, "[")
    // str = str.replace(/】/g, "]")
    // str = str.replace(/（/g, "(")
    // str = str.replace(/）/g, ")")
    // str = str.replace(/·/g, "`")
    // return str
}

/**
 * 尝试为某个组件设置 loading=true
 */
export function setLoading(sender: any) {
    if (sender) {
        try {
            sender.loading = true
        } catch (e) {
        }
    }
}

/**
 * 尝试为某个组件设置 loading=false
 */
export function setUnLoading(e: any) {
    if (e) {
        try {
            e.loading = false
        } catch (e) {
        }
    }
}

/**
 * 触发某个 YvanEvent 事件
 */
export function YvanEventDispatch(event: any, sender: any, ...args: any[]) {
    if (!event) {
        return;
    }

    if (args && args.length === 1 && _.isArguments(args[0])) {
        args = Array.prototype.slice.call(args[0])
    }

    let func = event;
    if (typeof event === 'string' && event) {
        func = sender.props.$context.scopeInstance[event]
    }

    if (typeof func !== 'function') {
        console.error('无法找到函数' + event, sender.props.$context.scopeInstance)
        throw new TypeError('无法找到事件函数')
    }

    if (!args || args.length == 0) {
        return func.apply(sender.props.$context.scopeInstance, [sender])
    } else {
        //@ts-ignore
        return func.apply(sender.props.$context.scopeInstance, [sender].concat(args))
    }
}

/**
 * 是否为异步对象
 */
export function isPromise(obj: any): obj is Promise<any> {
    return (obj && typeof obj.then === 'function')
}

/**
 * 解析任何 T | Promise<T> 的返回结果, 都转换为 Promise<T>
 */
export function applyValue<T>(result: PromiseMabe<T>): Promise<T> {
    // @ts-ignore
    if (result && typeof result.then === 'function') {
        return result as any
    }

    return new Promise<T>(resolve => {
        resolve(result)
    })
}

/**
 * 解析复杂可被观测属性定义
 */
export function applyComplexValue<T>(scope: any, valueDefine: ComplexPropertyValue<T>): Promise<T> {
    return new Promise<any>(resolve => {

        if (!valueDefine) {
            resolve(valueDefine)
            return
        }

        // @ts-ignore
        if (typeof valueDefine.$watch === 'function') {
            // 定义是 { $watch:()=> T|Promise<T> }
            // @ts-ignore
            applyValue(valueDefine.$watch.call(scope)).then((watchResult: any) => {

                // 定义是 { $watch:()=> any , $then:(watchResult:any)=> T|Promise<T> }
                // @ts-ignore
                if (typeof valueDefine.$then === 'function') {
                    // @ts-ignore
                    applyValue(valueDefine.$then.call(scope, watchResult)).then(res => {
                        resolve(res)
                    })

                } else {
                    resolve(watchResult)
                }
            })
            return
        }

        if (typeof valueDefine === 'function') {
            // 定义是 ()=> (T | Promise<T>)
            // @ts-ignore
            applyValue(valueDefine.call(scope)).then(res => {
                resolve(res)
            })

        } else {
            // 定义是 T
            resolve(valueDefine)
        }
    })
}

/**
 * 判断是否在双向绑定事务中
 */
export function inTransaction() {
    const inBatch = mobx._getGlobalState().inBatch
    return inBatch > 0
}

/**
 * 判断目标对象是否为 ReactElement 元素
 */
export function isReact<T>(obj: any): obj is ReactElement<T> {
    return React.isValidElement(obj)
}

function deepTraverObjectInner(hierarchyParent: any, parentPath: string, cb: (path: string, key: string, value: any) => void) {
    if (!hierarchyParent) {
        return
    }
    if (isReact(hierarchyParent)) {
        // 如果 hierarchy 对象本身是 React 对象，直接产生 key='' 的回调
        cb(parentPath, '', hierarchyParent)

    } else if (hierarchyParent.isValueDefine || typeof hierarchyParent === 'symbol') {
        // 如果 hierarchy 对象本身是 ValueDefine 对象，直接产生 key='' 的回调
        cb(parentPath, '', hierarchyParent)

    } else {
        _.forOwn(hierarchyParent, (v, k) => {
            const fullKey = parentPath ? parentPath + "." + k : k
            if (_.isPlainObject(v)) {
                deepTraverObjectInner(v, fullKey, cb)

            } else if (_.isArray(v)) {
                _.forEach(v, (item, idx) => {
                    deepTraverObjectInner(item, `${fullKey}[${idx}]`, cb)
                })

            } else {
                cb(fullKey, k, v)
            }
        })
    }
}

/**
 * 深度遍历多层级 JSON 的最终叶子节点, 传入一个 (path:string, key: string, value: any)=>void 回调
 * @param hierarchyObject
 * @param cb
 */
export function deepTraverObject(hierarchyObject: any, cb: (path: string, key: string, value: any) => void) {
    deepTraverObjectInner(hierarchyObject, '', cb)
}

function deepTraverPlanObjectInner(hierarchyParent: any, parentPath: string, cb: (path: string, key: string, value: any) => (boolean | 'continue' | void), viewDetail: boolean) {
    if (hierarchyParent.isValueDefine || typeof hierarchyParent === 'symbol') {
        // 如果 hierarchy 对象本身是 ValueDefine 对象，直接产生 key='' 的回调
        // cb(parentPath, '', hierarchyParent)

    } else {
        if (_.isPlainObject(hierarchyParent) && viewDetail === true) {
            const re = cb(parentPath, '', hierarchyParent);
            if (re === true) {
                throw Symbol('jumpOut')
            } else if (re === 'continue') {
                return
            }
        }
        try {
            _.forOwn(hierarchyParent, (v, k) => {
                const fullKey = parentPath ? parentPath + "." + k : k
                if (_.isPlainObject(v)) {
                    const re = cb(fullKey, k, v);
                    if (re === true) {
                        throw Symbol('jumpOut')
                    } else if (re === 'continue') {
                        return
                    }
                    deepTraverPlanObjectInner(v, fullKey, cb, viewDetail)

                } else if (_.isArray(v)) {
                    const re = cb(fullKey, k, v);
                    if (re === true) {
                        throw Symbol('jumpOut')
                    } else if (re === 'continue') {
                        return
                    }
                    _.forEach(v, (item, idx) => {
                        deepTraverPlanObjectInner(item, `${fullKey}[${idx}]`, cb, viewDetail)
                    })

                } else {
                    // 叶子节点，不再访问
                }
            })
        } catch (e) {
            // jumpOut 不是异常
            // console.error(e);
        }
    }
}

/**
 * 深度遍历多层级 JSON 的 Array或PlanObject 节点, 传入一个 (path:string, key: string, value: any)=>void 回调
 * 如果回调返回 true ，则不再进行递归. (因为会改变 hierarchyObject 对象本身)
 * @param hierarchyObject
 * @param cb
 */
export function deepTraverPlanObject(hierarchyObject: any, cb: (path: string, key: string, value: any) => (void | boolean), viewDetail: boolean = false) {
    deepTraverPlanObjectInner(hierarchyObject, '', cb, viewDetail)
}

/**
 * 为每一个组件创建一个 ID
 */
export function createViewId(view: string) {
    return _.uniqueId(view + '_')
}

/**
 * 创建一个 ID
 */
export function createId(name?: string) {
    return _.uniqueId(name || '_')
}

/**
 * 将 PlanObject或数组，变换为 { id, text } 数组
 */
export function getSelectData(obj: any) {
    if (_.isPlainObject(obj)) {
        const r: any[] = []
        _.forOwn(obj, (value, key) => {
            r.push({text: value, id: key})
        })
        return r
    } else if (_.isArray(obj)) {
        return obj
    }
    return []
}

/**
 * 执行一句函数表达式
 * @param me this对象
 * @param expression 表达式字符串
 * @param data 能参与表达式运算的数据范围
 */
export function evalExpression(me: any, expression: string, data?: object): boolean {
    if (!expression || typeof expression !== 'string') {
        return false;
    }

    /* jshint evil:true */
    let debug = false;
    const idx = expression.indexOf('debugger');
    if (~idx) {
        debug = true;
        expression = expression.replace(/debugger;?/, '');
    }

    const fn = new Function(
        'data',
        'utils',
        `with(data) {${debug ? 'debugger;' : ''}return (${expression});}`
    );
    data = data || {};
    return fn.call(me, data);
}